package com.cheche.dn.infrastructure.externalwebservice;

import com.cheche.dn.common.Filter;
import com.cheche.dn.common.base.Service;
import com.cheche.dn.domain.Authorities;
import com.cheche.dn.domain.admin.Admin;
import com.cheche.dn.domain.admin.AdminService;
import com.cheche.dn.domain.admin.Authority;
import com.cheche.dn.domain.admin.Role;
import com.cheche.dn.infrastructure.security.ExternalServiceAuthenticator;
import com.google.common.collect.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.Set;

/**
 * 管理员账号验证
 * Created by cheshun on 15/8/1.
 */
@Component("adminServiceAuthenticator")
public class AdminServiceAuthenticator implements ExternalServiceAuthenticator {

    @Autowired
    private Service service;
    @Autowired
    private AdminService adminService;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Value("${super.admin.username}")
    private String superAdminUsername;
    @Value("${super.admin.default.password}")
    private String superAdminPassword;
    @Value("${super.admin.role}")
    private String superAdminRole;

    @PostConstruct
    protected void initialize() {
        Set<Authority> authorities = Sets.newHashSet();
        Authority superAuthority = service.find(Authority.class, Filter.eq(Authority.NAME_PROPERTY_NAME, Authorities.SUPER_ADMIN.getName()));
        if (superAuthority == null) {
            superAuthority = Authorities.SUPER_ADMIN;
            service.save(superAuthority);
            authorities.add(superAuthority);
        } else {
            authorities.add(superAuthority);
        }
        for (Authority authority : Authorities.values) {
            Authority auth = service.find(Authority.class, Filter.eq(Authority.NAME_PROPERTY_NAME, authority.getName()));
            if (auth == null) {
                service.save(authority);
                authorities.add(authority);
            } else {
                authorities.add(auth);
            }
        }
        adminService.deleteAuthority(authorities);
        Role superRole = service.find(Role.class, Filter.eq(Role.NAME_PROPERTY_NAME, superAdminRole));
        if (superRole == null) {
            superRole = new Role();
            superRole.setName(superAdminRole);
            superRole.setIsSystem(true);
            superRole.setDescription("This is super admin.");
            superRole.setAuthorities(Sets.newHashSet(superAuthority));
            service.save(superRole);
        } else {
            superRole.setAuthorities(Sets.newHashSet(superAuthority));
            service.update(superRole);
        }
        if (!service.exists(Admin.class, Filter.eq(Admin.USERNAME_PROPERTY_NAME, superAdminUsername))) {
            Admin admin = new Admin();
            admin.setUsername(superAdminUsername);
            admin.setPassword(passwordEncoder.encode(superAdminPassword));
            admin.setNickname("超级管理员");
            admin.setRoles(Sets.newHashSet(superRole));
            service.save(admin);
        }

    }

    @Transactional(readOnly = true)
    @Override
    public PreAuthenticatedAuthenticationToken authenticate(String username, String password) {
        Admin admin = service.find(Admin.class, Filter.eq(Admin.USERNAME_PROPERTY_NAME, username));
        if (admin != null) {
            if (passwordEncoder.matches(password, admin.getPassword())) {
                return new PreAuthenticatedAuthenticationToken(admin, null, createAuthorities(admin));
            }
            throw new BadCredentialsException("Manager can not verification");
        }
        throw new UsernameNotFoundException("Username not found");
    }

    private Set<GrantedAuthority> createAuthorities(Admin admin) {
        Set<Role> roles = admin.getRoles();
        Set<GrantedAuthority> authorities = Sets.newHashSet();
        for (Role role : roles) {
            for (Authority authority : role.getAuthorities()) {
                authorities.add(new SimpleGrantedAuthority(authority.getName()));
            }
        }
        return authorities;
    }
}
